﻿using System;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using static Autodesk.AutoCAD.ApplicationServices.Core.Application;
using Line = Autodesk.AutoCAD.DatabaseServices.Line;
using Polyline = Autodesk.AutoCAD.DatabaseServices.Polyline;

namespace AutoCAD_CSharp_plug_in3.Chap03
{
    public static class DorBlock
    {
        private const string DorBlockName1 = "DorBlockName1";

        private const string DorLayerName = "DorLayerName";

        public static void InsertDorBlock()
        {
            var db = HostApplicationServices.WorkingDatabase;
            var ed = DocumentManager.MdiActiveDocument.Editor;

            do
            {
                var o2 = new PromptEntityOptions("\n选择一条线(直线或多段线): ");
                o2.SetRejectMessage("\n只能选择直线或多段线.");
                o2.AddAllowedClass(typeof(Line), false);
                o2.AddAllowedClass(typeof(Polyline), false);
                var l = ed.GetEntity(o2);
                if (l.Status != PromptStatus.OK) return;

                var o1 = new PromptPointOptions("\n在线上选择插入点: ");
                var p = ed.GetPoint(o1);
                if (p.Status != PromptStatus.OK) return;
                var selectedPoint = p.Value;

                using (var trans = db.TransactionManager.StartTransaction())
                {
                    try
                    {
                        var entity = (Entity)trans.GetObject(l.ObjectId, OpenMode.ForRead);

                        if (entity is Curve curve)
                        {
                            Point3d insertPoint = curve.GetClosestPointTo(selectedPoint, false);
                            Vector3d direction = curve.GetFirstDerivative(insertPoint);
                            double rotateAngle = Math.Atan2(direction.Y, direction.X);

                            switch (entity)
                            {
                                case Line line:
                                    ModifyAngle(line, ref rotateAngle);

                                    break;
                                case Polyline polyline:
                                    ModifyAngle(polyline, ref rotateAngle);

                                    break;
                                default:
                                    return;
                            }

                            using (DocumentManager.MdiActiveDocument.LockDocument())
                            {
                                db.CurrentSpaceId.InsertBlockReference(
                                    DorBlockName1,
                                    insertPoint,
                                    new Scale3d(1000),
                                    rotateAngle,
                                    DorLayerName,
                                    DorBlockName1,
                                    CreateNozzleEntity(DorBlockName1));
                            }
                        }

                        trans.Commit();
                    }
                    catch (Exception ex)
                    {
                        trans.Abort();
                        ed.WriteMessage($"\n插入失败: {ex.Message}");
                    }
                }
            } while (true);
        }

        private static void ModifyAngle(Polyline polyline, ref double rotateAngle)
        {
            if (!IsClockWise(polyline))
            {
                rotateAngle -= Math.PI;
            }
        }

        private static bool IsClockWise(Polyline polyline)
        {
            double area = 0;
            int count = polyline.NumberOfVertices;

            for (int i = 0; i < count; i++)
            {
                Point2d p1 = polyline.GetPoint2dAt(i);
                Point2d p2 = polyline.GetPoint2dAt((i + 1) % count);

                area += (p2.X - p1.X) * (p2.Y + p1.Y);
            }

            // 如果面积为正是顺时针；为负是逆时针
            return area > 0;
        }

        private static void ModifyAngle(Line line, ref double rotateAngle)
        {
            var startPoint = line.StartPoint;
            var endPoint = line.EndPoint;
            // 比较X坐标
            if (startPoint.X < endPoint.X)
            {
                // 从左到右绘制
                Console.WriteLine("");
            }
            else if (startPoint.X > endPoint.X)
            {
                // 从右到左绘制
                rotateAngle += Math.PI;
            }
            else
            {
                // 比较Y坐标
                if (startPoint.Y < endPoint.Y)
                {
                    // 从下到上绘制
                    Console.WriteLine("");
                }
                else if (startPoint.Y > endPoint.Y)
                {
                    // 从上到下绘制
                    rotateAngle -= Math.PI;
                }
            }
        }

        /// <summary>
        ///     create nozzle bolckrecord entity;
        /// </summary>
        /// <param name="bolckName"></param>
        /// <returns></returns>
        private static BlockTableRecord CreateNozzleEntity(string bolckName)
        {
            var btr = new BlockTableRecord();
            btr.Name = bolckName;


            // 创建圆弧参数
            var center = new Point3d(0.475, 0, 0);
            var radius = 0.975;
            var startAngle = AngleHelper.DegreesToRadians(91); // 0度
            var endAngle = AngleHelper.DegreesToRadians(180); // 90度

            // 创建圆弧对象
            var arc = new Arc(center, radius, startAngle, endAngle);


            //两竖线
            var lshuline1 = new Line(new Point3d(0.45, 0, 0), new Point3d(0.45, 0.975, 0));
            var lshuline2 = new Line(new Point3d(0.5, 0, 0), new Point3d(0.5, 0.975, 0));

            var lhenline1 = new Line(new Point3d(0.45, 0.975, 0), new Point3d(0.5, 0.975, 0));
            var lhenline2 = new Line(new Point3d(0.5, 0, 0), new Point3d(0.45, 0, 0));


            btr.AppendEntity(arc);
            btr.AppendEntity(lshuline1);
            btr.AppendEntity(lshuline2);
            btr.AppendEntity(lhenline1);
            btr.AppendEntity(lhenline2);

            return btr;
        }
    }
}